#ifndef RAMFS_TOOLS
#include <user/ulib.h>
#include <user/file_server.h>
#include <inc/env.h>
#else
#include "ramfstools.h"
#endif

static struct fs_node_t nodes[MAX_FS_NODE_COUNT];
static uint32_t free_head;

static struct fs_node_t *
get_free_node(void)
{
	 struct fs_node_t *result = nodes + free_head;
	 free_head = result->next - nodes;

	 /* 初始化标记和列表 */
	 mutex_init(&result->lock);

	 return result;
}

static void
free_node(struct fs_node_t *node)
{
	 node->next = nodes + free_head;
	 free_head = node - nodes;
}

#ifndef RAMFS_TOOLS
extern char fs_init_image[];
#endif

static struct fs_node_t *root;

int
init_fs(void)
{
	 /* 初始化文件分配 */
	 int i;
	 for (i = 0; i != MAX_FS_NODE_COUNT; ++i)
	 {
		  nodes[i].next = nodes + i + 1;
	 }

	 nodes[MAX_FS_NODE_COUNT - 1].next = NULL;

	 free_head = 0;

	 /* 载入初始的 ramfs 镜像 */
	 root = get_free_node();
	 create_ramfs(root);
	 
#ifndef RAMFS_TOOLS
	 import_ramfs((struct iramfs_node_t *)fs_init_image, root);
#else
	 FILE *f;
	 f = fopen("fsimage", "r");
	 int l;
	 
	 if (f != NULL)
	 {
		  fseek(f, 0, SEEK_END);
		  l = ftell(f);
		  fseek(f, 0, SEEK_SET);

		  char *buf = malloc(l);
		  fread(buf, 1, l, f);

		  import_ramfs((struct iramfs_node_t *)buf, root);

		  fclose(f);
	 }
#endif

	 root->ref_count = 1;	 
	 return 0;
}

#ifndef RAMFS_TOOLS

void
fs_dispath(void)
{
	 struct env_t *env = envs + self_idx;
	 uint16_t idx;
	 uint32_t num;
	 struct pipe_t *in_pipe, *out_pipe;

	 set_user_service(SVC_FILE_SERVER, self_idx);
	 kprintf("[fileserver] start, %08x\n", service_callback);

	 out_pipe = pipe_open(service_callback);

	 uint32_t zero = 0;
	 pipe_block_write(out_pipe, &zero, sizeof(uint32_t));
	 
	 pipe_close(out_pipe);
	 
	 while (1)
	 {
		  kprintf("[fileserver] listening\n");
		  // start to recv request
		  rpc_recv(&idx, &num, &in_pipe, &out_pipe);
		  kprintf("[fileserver] get request, num = %d\n", num);
		  

		  uint32_t n, dir, result;
		  struct fs_node_t *f;
		  char *buf;
		  
		  switch (num)
		  {
		  case FSC_SEEK:

			   pipe_block_read(in_pipe, &f, sizeof(uint32_t));
			   pipe_block_read(in_pipe, &dir, sizeof(uint32_t));
			   pipe_block_read(in_pipe, &n, sizeof(uint32_t));

			   result = fs_seek(f, dir, n);
			   
			   pipe_block_write(out_pipe, &result, sizeof(uint32_t));

			   // free(buf);

			   break;
		  case FSC_READ:

			   pipe_block_read(in_pipe, &f, sizeof(uint32_t));
			   pipe_block_read(in_pipe, &n, sizeof(uint32_t));
			   buf = (char *)malloc(n);

			   result = fs_read(f, buf, n);
			   pipe_block_write(out_pipe, &result, sizeof(uint32_t));
			   pipe_block_write(out_pipe, buf, result);

			   // free(buf);

			   break;
			   
		  case FSC_WRITE:

			   pipe_block_read(in_pipe, &f, sizeof(uint32_t));
			   pipe_block_read(in_pipe, &n, sizeof(uint32_t));
			   buf = (char *)malloc(n);
			   pipe_block_read(in_pipe, buf, n);

			   result = fs_write(f, buf, n);

			   pipe_block_write(out_pipe, &result, sizeof(uint32_t));
			   // free(buf);

			   break;

		  case FSC_OPEN_ROOT:
			   
			   result = (uint32_t)open_root();
			   pipe_block_write(out_pipe, &result, sizeof(uint32_t));
			   
			   break;

		  case FSC_OPEN:

			   pipe_block_read(in_pipe, &f, sizeof(uint32_t));
			   result = (uint32_t)fs_open(f);
			   pipe_block_write(out_pipe, &result, sizeof(uint32_t));

			   break;
		  }

		  rpc_return(idx, in_pipe, out_pipe);
	 }
}

void
file_server_entry()
{
	 init_ramfs_driver();
	 init_fs();
	 fs_dispath();
}
#endif

static struct fs_node_t *root;

struct fs_node_t *
open_root()
{
	 return fs_dup(root);
}

#ifdef RAMFS_TOOLS
void
dump_root(void)
{
	 FILE *f;
	 f = fopen("fsimage", "w");
	 export_ramfs(f, (void (*)(char, void *))fputc, root);
	 fclose(f);
}
#endif

int
fs_read(struct fs_node_t *f, void *buf, int n)
{
	 if (f->dev->read == NULL) return 0;
	 return f->dev->read(f, buf, n);
}

int
fs_write(struct fs_node_t *f, void *buf, int n)
{
	 if (f->dev->write == NULL) return 0;
	 return f->dev->write(f, buf, n);
}

int
fs_seek(struct fs_node_t *f, int dir, int n)
{
	 return f->dev->seek(f, dir, n);
}

struct fs_node_t *
fs_open(struct fs_node_t *d)
{
	 struct fs_node_t *result = get_free_node();
	 if (d->dev->open(d, result) != 0)
	 {
		  free_node(result);
		  result = NULL;
	 }

	 return result;
}

int
fs_stat(struct fs_node_t *d, struct fs_stat_t *attr)
{
	 return d->dev->stat(d, attr);
}

int
fs_close(struct fs_node_t *f)
{
	 if (--f->ref_count == 0)
	 {
		  f->dev->close(f);
		  free_node(f);
	 }

	 return 0;
}

int
fs_roll(struct fs_node_t *d)
{
	 return d->dev->roll(d);
}

int
fs_create(struct fs_stat_t *attr, char *filename, int n, struct fs_node_t *d)
{
	 return d->dev->create(attr, filename, n, d);
}

int
fs_remove(struct fs_node_t *d)
{
	 return d->dev->remove(d);
}

int
fs_move(struct fs_node_t *s, struct fs_node_t *d)
{
	 return d->dev->move(s, d);
}

struct fs_node_t *
fs_dup(struct fs_node_t *s)
{
	s->ref_count++;
	return s;
}

struct fs_node_t *
fs_copynode(struct fs_node_t *s)
{
	struct fs_node_t *d = get_free_node();
	d->ref_count = 1;
	d->dev = s->dev;
	d->type = s->type;
	mutex_init(&d->lock);
	if (d->dev->copynode(s, d))
	{
		free(d);
		return NULL;
	}
	else
		return d;
}

